package org.setamv.springcloud.feign.raw;

import com.netflix.client.ClientFactory;
import com.netflix.client.http.HttpRequest;
import com.netflix.config.ConfigurationManager;
import com.netflix.niws.client.http.RestClient;
import feign.Client;
import feign.Request;
import feign.Request.Options;
import feign.Response;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.HashMap;

/**
 * 扩展feign的client接口，用于执行feing的http请求。并且利用ribbon实现负载均衡
 */
public class CustomizedHttpClient implements Client {

    public CustomizedHttpClient() {
        // 从配置文件ribbon-client.properties初始化ribbon的配置
        try {
            ConfigurationManager.loadPropertiesFromResources("ribbon-client.properties");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Response execute(Request request, Options options) throws IOException {
        System.out.println("进入自定义的HttpClient");
        long startTime = System.currentTimeMillis();
        // 通过其他的http代理来访问请求
        //        Response response = delegateByHttpClient(request);
        Response response = delegateByRibbonLoadBalance(request);
        long endTime = System.currentTimeMillis();
        System.out.println("请求使用时间：" + (endTime - startTime) + "ms");
        return response;
    }

    /**
     * 通过ribbon的负载均衡器实现请求的代理
     */
    public Response delegateByRibbonLoadBalance(Request request) {
        try {
            URI uri = new URI(request.url());
            RestClient client = (RestClient) ClientFactory.getNamedClient("service");
            HttpRequest ribbonRequest = HttpRequest.newBuilder().uri(uri.getPath()).build();
            com.netflix.client.http.HttpResponse ribbonResponse = client.executeWithLoadBalancer(ribbonRequest);

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int len = -1;
            while ((len = ribbonResponse.getInputStream().read(buf)) != -1) {
                bos.write(buf, 0, len);
            }
            Response response = Response.builder()
                    .body(bos.toByteArray())
                    .headers(new HashMap<String, Collection<String>>())
                    .status(ribbonResponse.getStatus())
                    .build();
            return response;
        } catch (Exception e) {
            throw new RuntimeException("error", e);
        }
    }

    /**
     * 通过HttpClient实现代理
     */
    public Response delegateByHttpClient(Request request) {
        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpRequestBase httpRequest = new HttpRequestBase() {
                @Override
                public String getMethod() {
                    return request.method();
                }
            };
            httpRequest.setURI(new URI(request.url()));
            HttpResponse httpResponse = httpClient.execute(httpRequest);
            byte[] body = EntityUtils.toByteArray(httpResponse.getEntity());
            Response response = Response.builder()
                                        .body(body)
                                        .headers(new HashMap<String, Collection<String>>())
                                        .status(httpResponse.getStatusLine().getStatusCode())
                                        .build();
            return response;
        } catch (Exception e) {
            throw new RuntimeException("error", e);
        }
    }
}
